home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 21
/
Cream of the Crop 21 (Terry Blount) (October 1996).iso
/
program
/
oxcc1434.zip
/
SRC
/
OBJ4LB.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-10-24
|
22KB
|
1,017 lines
/* obj4lb.c -- fiddle with symbols in an a.out or coff format file
** Copyright (C) 1995 Norman D. Culver All rights reserved.
**
** COMPILE: (using djcc v1.12)
** gcc -O2 -o obj4lb obj4lb.c
** coff2exe -s go32.exe obj4lb
*/
#include <dos.h>
#include <limits.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdarg.h>
#include <memory.h>
#include <string.h>
#include <stdio.h>
#include <binimg.h>
#define coff_sym_is_fortrancommon(p) \
((p->e_sclass == C_EXT) && (p->e_scnum == 0) && (p->e_value != 0))
#define coff_sym_is_undefined(p) \
((p->e_scnum == 0) && (p->e_sclass == C_EXT))
#define coff_sym_is_global(p) \
(p->e_sclass == C_EXT)
/* USEFUL DEFINITIONS */
#ifndef __GNUC__
typedef unsigned int u_int;
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned long u_long;
#endif
typedef union {
u_short val;
u_char b[2];
} SVAL;
typedef union {
u_long a0;
void *a1;
struct {
SVAL offset;
SVAL seg_addr;
}a2;
} ADDR;
typedef struct _exports {
struct _exports *fptr;
char *name;
int len;
} EXPORTS;
typedef struct _renames {
struct _renames *fptr;
char *oldname;
int oldlen;
char *newname;
int newlen;
} RENAMES;
typedef struct _movdat {
struct _movdat *fptr;
unsigned long offset;
} MOVDAT, *PMOVDAT;
typedef struct relocation_info RELINFO;
#define round_up(size,amt) \
((size&(amt-1)) ? size+(amt-(size&(amt-1))) : size)
/* LOCAL VARIABLES */
static char infile[128];
static char outfile[128];
static char lb4file[128];
static struct exec header;
static FILE *ifd, *lb4fd, *ofd;
static EXPORTS exports;
static RENAMES renames;
static EXPORTS *lexports;
static RENAMES *lrenames;
static MOVDAT moves;
static MOVDAT *lmoves;
static int rename_diftot;
static long lowoffset;
static char *strtbl;
static char *nstrtbl;
static long strsize;
static long nstrsize;
static int nsyms;
/* INPUT DATA FROM THE .o FILE */
static NLIST *symtbl;
static char *text;
static RELINFO *text_relocs;
static int n_text_relocs;
static char *data;
static RELINFO *data_relocs;
static int n_data_relocs;
/* coff stuff */
typedef struct oxhdr {
unsigned short info;
unsigned short machine;
unsigned start_addr;
unsigned text_vaddr;
unsigned text_size;
unsigned text_fileaddr;
unsigned data_vaddr;
unsigned data_size;
unsigned data_fileaddr;
unsigned bss_vaddr;
unsigned bss_size;
unsigned image_size;
unsigned text_reloc_fileaddr;
unsigned text_reloc_size;
unsigned text_reloc_cnt;
unsigned data_reloc_fileaddr;
unsigned data_reloc_size;
unsigned data_reloc_cnt;
unsigned symbols_fileaddr;
unsigned symbols_size;
unsigned symbols_cnt;
unsigned strings_fileaddr;
unsigned strings_size;
unsigned section_headers_size;
} OXHDR, *POXHDR;
typedef struct {
void *addr;
long size;
unsigned long fileptr;
long cnt;
} BUFS, *PBUFS;
static OXHDR xhdr;
static unsigned char scntype[128];
static PSCNHDR t,d,b,q,s;
static PBUFS sbf;
static PBUFS rbf;
static PBUFS lbf;
static PCOFF_SYMBOL coff_symtbl;
static short bss_section;
/* start of subroutines */
static void *
xmalloc (long n)
{
void *p;
p = calloc (1,(size_t)n);
if (n > 0 && p == 0)
{
puts ("obj4lb: virtual memory exhausted");
exit (1);
}
return p;
}
static int
isglobal(char *str)
{
EXPORTS *l = &exports;
while(l->fptr)
{
l = l->fptr;
if(!strcmp(str, l->name))
return 1;
}
return 0;
}
static RENAMES *
isrenamed(char *str)
{
RENAMES *r = &renames;
while(r->fptr)
{
r = r->fptr;
if(!strcmp(str, r->oldname))
return r;
}
return NULL;
}
static void
aout_get_rid_of_fortrancommon(NLIST *sp, int symidx, int setglobal)
{/* move fortrancommon symbols to the bss segment */
u_long bssbase = N_BSSADDR(header);
u_long bssoffset = round_up(header.a_bss, sizeof(int));
u_long symbsize = sp->n_value;
u_long bssaddr = bssbase + bssoffset;
RELINFO *r;
int i;
void *ldata;
sp->n_value = bssaddr;
if(setglobal)
sp->n_type = N_BSS|N_EXT;
else
sp->n_type = N_BSS;
header.a_bss = bssoffset + symbsize;
/* adjust all relocs which refence this variable */
for(i = 0, r=text_relocs; i < n_text_relocs; ++i, ++r)
{
if(r->r_extern && r->r_symbolnum == symidx)
{
ldata = &text[r->r_address];
r->r_extern = 0;
r->r_symbolnum = N_BSS;
if(r->r_length == 2)
*((long *)ldata) += bssaddr;
else
{
puts("4lb: non 32bit reloc encountered");
exit(1);
}
}
}
for(i = 0, r=data_relocs; i < n_data_relocs; ++i, ++r)
{
if(r->r_extern && r->r_symbolnum == symidx)
{
ldata = &data[r->r_address];
r->r_extern = 0;
r->r_symbolnum = N_BSS;
if(r->r_length == 2)
*((long *)ldata) += bssaddr;
else
{
puts("4lb: non 32bit reloc encountered");
exit(1);
}
}
}
}
static void
aout_adjust_symbol(long oldoffset, long newoffset, int setglobal)
{
NLIST *sp;
int i;
for(i = 0, sp = symtbl; i < nsyms; ++i, ++sp)
{
if(sp->n_un.n_strx == oldoffset)
{/* newoffset is set negative to avoid reuse */
sp->n_un.n_strx = newoffset | 0x80000000;
if(sym_is_fortrancommon(sp))
aout_get_rid_of_fortrancommon(sp, i, setglobal);
else if(setglobal)
sp->n_type |= N_EXT;
else if(!sym_is_undefined(sp))
sp->n_type &= ~N_EXT;
return;
}
}
}
static void
coff_get_rid_of_fortrancommon(COFF_SYMBOL *sp, int symidx, int setglobal)
{/* move fortrancommon symbols to the bss segment */
PCOFF_HDR p = (PCOFF_HDR)&header;
u_long bssbase = b->s_vaddr;
u_long bssoffset = round_up(b->s_size, sizeof(int));
u_long symbsize = sp->e_value;
u_long bssaddr = bssbase + bssoffset;
int i, j;
sp->e_value = bssaddr;
sp->e_scnum = bss_section;
if(setglobal)
sp->e_sclass = C_EXT;
else
sp->e_sclass = C_STAT;
b->s_size = round_up(bssoffset + symbsize, sizeof(int));
/* adjust all relocs which reference this variable */
for(i = 0; i < p->f_nscns; ++i)
{
COFF_RELOC *r;
if((r = rbf[i].addr))
{
int cnt = rbf[i].cnt;
char *scndata = sbf[i].addr;
unsigned long s_vaddr = s[i].s_vaddr;
for(j = 0; j < cnt; ++j, ++r)
{
if(r->r_symndx == symidx)
{
void *ldata = &scndata[r->u.r_vaddr - s_vaddr];
if(r->r_type == 0x0006)
{
*((long *)ldata) += bssaddr - symbsize;
}
else if(r->r_type == 0x0007)
{
puts("4lb: type 7 reloc encountered");
exit(1);
}
else if(r->r_type == 0x0014)
{
puts("4lb: pcrel comdef encountered");
exit(1);
}
else
{
puts("4lb: non 32bit reloc encountered");
exit(1);
}
}
}
}
}
}
static void
coff_adjust_symbol(long oldoffset, long newoffset, int setglobal)
{
COFF_SYMBOL *sp;
int i;
for(i = 0, sp = coff_symtbl; i < nsyms; ++i, ++sp)
{
if(sp->e.e.e_offset == oldoffset)
{/* newoffset is set negative to avoid reuse */
sp->e.e.e_offset = newoffset | 0x80000000;
if(coff_sym_is_fortrancommon(sp))
coff_get_rid_of_fortrancommon(sp, i, setglobal);
else if(setglobal)
sp->e_sclass = C_EXT;
else if(!coff_sym_is_undefined(sp))
{
if(coff_sym_is_global(sp))
sp->e_sclass = C_STAT;
}
}
if(sp->e_numaux)
{/* ignore aux records */
i += sp->e_numaux;
sp += sp->e_numaux;
}
}
}
static void
adjust_strings(int format_fudge)
{/* HERE'S THE BEEF -- WRITE A NEW STRING TABLE AND ADJUST SYMTAB */
long istroff = lowoffset;
long ostroff = lowoffset;
char *ip, *ep, *op;
int i;
nstrsize = strsize + rename_diftot;
nstrtbl = xmalloc(nstrsize+12);
ip = strtbl+lowoffset;
op = nstrtbl+lowoffset;
ep = ip + strsize;
while(ip < ep)
{/* scan over each of the strings in the old string table */
int global;
int istrlen = strlen(ip);
int olen;
RENAMES *r;
if(istrlen > 0)
{
if((r = isrenamed(ip)))
{/* change the string on output */
strcpy(op, r->newname);
op += r->newlen+1;
olen = r->newlen+1;
global = isglobal(r->newname);
}
else
{/* use the